//! \file GuiCEGUI.cpp
//! \brief TODO: Document
// -----------------------------------------------------------------------------
//! This program is free software; you can redistribute it and/or
//! modify it under the terms of the GNU General Public License
//! as published by the Free Software Foundation; either version 2
//! of the License, or (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program; if not, write to the Free Software Foundation,
//! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// -----------------------------------------------------------------------------

#include "GuiCEGUI.h"
#include "Core.h"
//#include <SDL/SDL.h>
#include "MenuMain.h" // TODO: remove after testing

using namespace CEGUI;

// =====[ Local Definitions ]===================================================

// =====[ Local DataTypes ]=====================================================

// =====[ Local Variables ]=====================================================
GuiCEGUI* GuiCEGUI::m_pGuiCEGUI = NULL;   //!< The singleton object instance.
WindowManager *GuiCEGUI::m_pWm = NULL;    //!< TODO: document
System *GuiCEGUI::m_pSystem = NULL;       //!< TODO: document the gui system
Window *GuiCEGUI::m_pRoot = NULL;         //!< TODO: document
Font *GuiCEGUI::m_pFont = NULL;           //!< TODO: document
double GuiCEGUI::m_PreviousTick;          //!< TODO: document

// =====[ Local Functions ]=====================================================

// =====[ Private (Internal) Methods ]==========================================

// =====[ Local Implementation ]================================================


// =============================================================================
// GuiCEGUI::getSingleton
// -----------------------------------------------------------------------------
//! Returns a reference to the instanced singleton object.
//!
//! \retval Singleton
//!   A reference to the instanced singleton object.
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
GuiCEGUI& GuiCEGUI::getSingleton()
{
  // Only allow one instance of class to be generated.
  if (!m_pGuiCEGUI) { m_pGuiCEGUI = new GuiCEGUI; }   // Create our single instance.
  return (*m_pGuiCEGUI);                          // Finally, return our singleton.
}


// =============================================================================
// GuiCEGUI::getSingletonPtr
// -----------------------------------------------------------------------------
//! Returns a pointer to the instanced singleton object.
//!
//! \retval Singleton
//!   A pointer to the instanced singleton object.
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
GuiCEGUI* GuiCEGUI::getSingletonPtr()
{
  // Only allow one instance of class to be generated.
  if (!m_pGuiCEGUI) { m_pGuiCEGUI = new GuiCEGUI; }   // Create our single instance.
  return (m_pGuiCEGUI);                           // Finally, return our singleton.
}


// =============================================================================
// GuiCEGUI::start
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GuiCEGUI::start(void)
{
  tERROR Error;

  // Connect CEGUI up with the OpenGL renderer.
  OpenGLRenderer::bootstrapSystem();

  // Initialize the resource provider.
  if ((Error = createResourceProvider()) != ERR_NONE) { return (Error); }

  // Create (load) the TaharezLook scheme file (this auto-loads the
  // TaharezLook looknfeel and imageset files).
  SchemeManager::getSingleton().create("TaharezLook.scheme");

  // Create (load) a font.  The first font loaded automatically becomes the
  // default font, but note that the scheme might have already loaded a font,
  // so there may already be a default set - if we want the "Commonweath-10"
  // font to definitely be the default, we should set the default explicitly
  // afterwards.
  m_pFont = &(FontManager::getSingleton().create("DejaVuSans-10.font"));

/*
  //System::getSingleton().setDefaultFont( "DejaVuSans-10" ); TODO: something??
  // Load the default font. TODO: load during the init stuff...
  pFont = &FontManager::getSingleton().create("DejaVuSans-10.font");
  */

  // TODO: comment
  System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow");
  // System::getSingleton().setDefaultToolTip( "TaharezLook/Tooltip" );

  // Grab a reference to the system.
  m_pSystem = System::getSingletonPtr();

  // Grab a reference to the window manager.
  m_pWm = WindowManager::getSingletonPtr();

  // Create the root windows.
  m_pRoot = m_pWm->createWindow( "DefaultWindow", "root" );

  // Set the root to be the active sheet.
  System::getSingleton().setGUISheet(m_pRoot);

  // TODO: comment
  m_PreviousTick = (0.001 * static_cast<double>(SDL_GetTicks()));

//  // TODO: comment
//  CreateCEGUIRoot();

  // Return success.
  return (ERR_NONE);
}


// =============================================================================
// GuiCEGUI::stop
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GuiCEGUI::stop(tERROR Error)
{
  // Return the original error code.
  return (Error);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
WindowManager *GuiCEGUI::getWm(void)
{
  return (m_pWm);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
System *GuiCEGUI::getSystem(void)
{
  return (m_pSystem);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
Window *GuiCEGUI::getRoot(void)
{
  return (m_pRoot);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
Font *GuiCEGUI::getFont(void)
{
  return (m_pFont);
}


// =============================================================================
// GuiCEGUI::inject
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::inject(void)
{
  injectInput();
  injectTime();
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::render(void)
{
  // Render CEGUI.
  System::getSingleton().renderGUI();
}


// =============================================================================
// GuiCEGUI::createResourceProvider
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
tERROR GuiCEGUI::createResourceProvider(void)
{
  // Initialize the required directories for the DefaultResourceProvider.
  DefaultResourceProvider *pRp =
      static_cast<DefaultResourceProvider*> (System::getSingleton().getResourceProvider());

  // Set the resource group directory paths.
  pRp->setResourceGroupDirectory("schemes", "./datafiles/schemes/");
  pRp->setResourceGroupDirectory("imagesets", "./datafiles/imagesets/");
  pRp->setResourceGroupDirectory("fonts", "./datafiles/fonts/");
  pRp->setResourceGroupDirectory("layouts", "./datafiles/layouts/");
  pRp->setResourceGroupDirectory("looknfeels", "./datafiles/looknfeel/");
  pRp->setResourceGroupDirectory("lua_scripts", "./datafiles/lua_scripts/");

  // This is only needed when using Xerces and to specify the schemas location.
  pRp->setResourceGroupDirectory("schemas", "./datafiles/xml_schemas/");

  // Set the default resource groups to be used.
  Imageset::setDefaultResourceGroup("imagesets");
  Font::setDefaultResourceGroup("fonts");
  Scheme::setDefaultResourceGroup("schemes");
  WidgetLookManager::setDefaultResourceGroup("looknfeels");
  WindowManager::setDefaultResourceGroup("layouts");
  ScriptModule::setDefaultResourceGroup("lua_scripts");

  // Setup default group for validation schemas.
  XMLParser* pParser = System::getSingleton().getXMLParser();
  if (pParser->isPropertyPresent("SchemaDefaultResourceGroup"))
    { pParser->setProperty("SchemaDefaultResourceGroup", "schemas"); }

  // Return success.
  return (ERR_NONE);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::injectInput(void)
{
  SDL_Event Event;

  // Process all available events.
  while (SDL_PollEvent(&Event))
  {
    // Determine the event type.
    switch (Event.type)
    {
      // Mouse motion.
      case SDL_MOUSEMOTION:
        // we inject the mouse position directly.
        System::getSingleton().injectMousePosition(
          static_cast<float>(Event.motion.x),
          static_cast<float>(Event.motion.y)
        );
        break;

      // Mouse down.
      case SDL_MOUSEBUTTONDOWN:
        // let a special function handle the mouse button down event
        mouseDown(Event.button.button);
        break;

      // Mouse up.
      case SDL_MOUSEBUTTONUP:
        // let a special function handle the mouse button up event
        mouseUp(Event.button.button);
        break;

      // Key down.
      case SDL_KEYDOWN:
        // to tell CEGUI that a key was pressed, we inject the scan code.
        System::getSingleton().injectKeyDown(Event.key.keysym.scancode);

        // as for the character it's a little more complicated. we'll use for translated unicode value.
        // this is described in more detail below.
        if (Event.key.keysym.unicode != 0)
        {
          System::getSingleton().injectChar(Event.key.keysym.unicode);
        }

        // TODO: temporary handling for now...
        if (Event.key.keysym.sym == SDLK_ESCAPE)
          { Core::TaskRequestShutdown(ERR_NONE); }

        break;

      // key up
      case SDL_KEYUP:
        // like before we inject the scan code directly.
        System::getSingleton().injectKeyUp(Event.key.keysym.scancode);
        break;


      // WM quit event occurred
      case SDL_QUIT:
        // must_quit = true;
        Core::TaskRequestShutdown(ERR_NONE);
        break;

    }

  }

}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::injectTime(void)
{
  // Get the current SDL run time "ticks".
  double Ticks = 0.001*SDL_GetTicks();

  // Inject the time that passed since the last call to CEGUI.
  System::getSingleton().injectTimePulse(float(Ticks - m_PreviousTick));

  // Save our tick for later.
  m_PreviousTick = Ticks;
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::mouseDown(Uint8 Button)
{
  switch (Button)
  {
    case SDL_BUTTON_LEFT:
      System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton);
      break;
    case SDL_BUTTON_MIDDLE:
      System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
      break;
    case SDL_BUTTON_RIGHT:
      System::getSingleton().injectMouseButtonDown(CEGUI::RightButton);
      break;
    case SDL_BUTTON_WHEELDOWN:
      System::getSingleton().injectMouseWheelChange( -1 );
      break;
    case SDL_BUTTON_WHEELUP:
      System::getSingleton().injectMouseWheelChange( +1 );
      break;
  }
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
void GuiCEGUI::mouseUp(Uint8 Button)
{
  switch (Button)
  {
    case SDL_BUTTON_LEFT:
      System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton);
      break;
    case SDL_BUTTON_MIDDLE:
      System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton);
      break;
    case SDL_BUTTON_RIGHT:
      System::getSingleton().injectMouseButtonUp(CEGUI::RightButton);
      break;
  }
}


